package com.jiazixuan.stock.service.impl;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.io.BaseEncoding;
import com.jiazixuan.stock.constant.StockConstant;
import com.jiazixuan.stock.mapper.SysPermissionMapper;
import com.jiazixuan.stock.mapper.SysRolePermissionMapper;
import com.jiazixuan.stock.mapper.SysUserMapper;
import com.jiazixuan.stock.mapper.SysUserRoleMapper;
import com.jiazixuan.stock.pojo.domain.MenusPermDomain;
import com.jiazixuan.stock.pojo.domain.SysUserDomain;
import com.jiazixuan.stock.pojo.domain.User;
import com.jiazixuan.stock.pojo.entity.SysPermission;
import com.jiazixuan.stock.pojo.entity.SysUser;
import com.jiazixuan.stock.service.UserService;
import com.jiazixuan.stock.utils.IdWorker;
import com.jiazixuan.stock.vo.req.AddUserReqVo;
import com.jiazixuan.stock.vo.req.LoginReqUsers;
import com.jiazixuan.stock.vo.req.LoginReqVo;
import com.jiazixuan.stock.vo.req.SysUserUpdateReqVo;
import com.jiazixuan.stock.vo.resp.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.management.relation.RoleInfo;
import java.awt.*;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service("userServiceImpl")
@Slf4j
public class UserServiceImpl implements UserService {

    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private SysUserRoleMapper sysUserRoleMapper;

    @Autowired
    private SysRolePermissionMapper sysRolePermissionMapper;

    @Autowired
    private SysPermissionMapper sysPermissionMapper;
    /**
     * 分布式环境保证生成的id唯一
     */
    @Autowired
    private IdWorker idWorker;

    @Override
    public SysUser findByUserName(String userName) {
        return sysUserMapper.findUserInfoByUserName(userName);
    }

//    @Override
//    public R<LoginRespVo> login(LoginReqVo vo) {
        //第一版
//        //1.判断请求数据是否合理
//        if (vo==null|| StringUtils.isBlank(vo.getUsername())||StringUtils.isBlank(vo.getPassword())) {
//            return R.error(ResponseCode.DATA_ERROR.getMessage());
//        }
//        //校验验证码和sessionId是否有效
//        if (StringUtils.isBlank(vo.getCode())||StringUtils.isBlank(vo.getSessionId())) {
//            return R.error(ResponseCode.CHECK_CODE_NOT_EMPTY);
//        }
//        //从redis中获取缓存的验证码（code）,使用key取value
//        String redisCode = (String) redisTemplate.opsForValue().get(StockConstant.CHECK_PREFIX + vo.getSessionId());
//        //判断获取的验证码是否存在（若不存在则证明redis中的sessionId已过期。），以及是否与输入的验证码相同
//            if(StringUtils.isBlank(redisCode)){
//                //验证码不存在证明redis中的sessionId已过期
//                R.error(ResponseCode.CHECK_CODE_TIMEOUT);
//            }
//            if(!redisCode.equalsIgnoreCase(vo.getCode())){
//                //验证码有误
//                R.error(ResponseCode.CHECK_CODE_ERROR);
//            }
//        //2.判断用户名是否存在（先根据用户名查询用户信息）
//        SysUser user = sysUserMapper.findUserInfoByUserName(vo.getUsername());
//        //判断用户是否存在，若存在，则密码校验对比
//        if (user==null||!passwordEncoder.matches(vo.getPassword(),user.getPassword())) {
//            return R.error(ResponseCode.USERNAME_OR_PASSWORD_ERROR.getMessage());
//        }
//        //组装登录成功数据
//        LoginRespVo respVo = new LoginRespVo();
//        //属性名称与类型必须相同，否则属性值无法copy
//        BeanUtils.copyProperties(user,respVo);
//        return R.ok(respVo);

//    }

    @Override
    public R<LoginRespVoWithMenusAndPermissions> login(LoginReqVo vo) {
        //优化
        //1.判断请求数据是否合理
        if (vo==null|| StringUtils.isBlank(vo.getUsername())||StringUtils.isBlank(vo.getPassword())) {
            return R.error(ResponseCode.DATA_ERROR.getMessage());
        }
        //校验验证码和sessionId是否有效
        if (StringUtils.isBlank(vo.getCode())||StringUtils.isBlank(vo.getSessionId())) {
            return R.error(ResponseCode.CHECK_CODE_NOT_EMPTY);
        }
        //从redis中获取缓存的验证码（code）,使用key取value
        String redisCode = (String) redisTemplate.opsForValue().get(StockConstant.CHECK_PREFIX + vo.getSessionId());
        //判断获取的验证码是否存在（若不存在则证明redis中的sessionId已过期。），以及是否与输入的验证码相同
        if(StringUtils.isBlank(redisCode)){
            //验证码不存在证明redis中的sessionId已过期
            return R.error(ResponseCode.CHECK_CODE_TIMEOUT);
        }
        if(!redisCode.equalsIgnoreCase(vo.getCode())){
            //验证码有误
            return R.error(ResponseCode.CHECK_CODE_ERROR);
        }
        //2.判断用户名是否存在（先根据用户名查询用户信息）
        SysUser user = sysUserMapper.findUserInfoByUserName(vo.getUsername());
        //判断用户是否存在，若存在，则密码校验对比
        if (user==null||!passwordEncoder.matches(vo.getPassword(),user.getPassword())) {
            return R.error(ResponseCode.USERNAME_OR_PASSWORD_ERROR.getMessage());
        }

        //根据用户id查找角色id（集合）
        List<Long> roleId = sysUserRoleMapper.getRoleIdByUserId(user.getId());
        //根据角色id获取权限id（集合）
        List<SysPermission> permissions = sysPermissionMapper.getPermissionByRoleId(roleId);
        //递归获取菜单权限过滤掉按钮权限
        List<MenusPermDomain> permissionTree = MenusPermDomain.digui(permissions,0l);
        log.info("权限树：{}",permissionTree);
        //获取按钮权限
        List<String> ButtonPermission = permissions.stream()
                .filter(p -> p.getType().intValue() == 3)
                .map(p -> p.getCode())
                .collect(Collectors.toList());
        log.info("权限按钮：{}",ButtonPermission);
        //整合数据
        //根据用户名字获取用户的基本信息
        User userInfo = sysUserMapper.getUserByUserName(vo.getUsername());
        log.info("用户的基本信息：{}",userInfo);
        //封装
        LoginRespVoWithMenusAndPermissions info = new LoginRespVoWithMenusAndPermissions(userInfo);
        info.setMenus(permissionTree);
        info.setPermissions(ButtonPermission);
        //设置加密id和名字
//        String idAndName = userInfo.getId()+":"+userInfo.getUsername();
//        String encodeInfo = BaseEncoding.base64().encode(idAndName.getBytes());
//        info.setAccessToken(encodeInfo);
        return R.ok(info);
    }

    /**
     * 生成登录校验码的访问接口
     * @return
     */
    @Override
    public R<Map> getCaptchaCode() {
        //参数分别是宽、高、验证码长度、干扰线数量
        LineCaptcha captcha = CaptchaUtil.createLineCaptcha(250, 40, 4, 5);
        //设置背景颜色清灰
        captcha.setBackground(Color.lightGray);
        //自定义校验码生成方式
//        captcha.setGenerator(new CodeGenerator() {
//            @Override
//            public String generate() {
//                return RandomStringUtils.randomNumeric(4);
//            }
//            @Override
//            public boolean verify(String code, String userInputCode) {
//                return code.equalsIgnoreCase(userInputCode);
//            }
//        });
        //获取图片中的验证码，默认生成的校验码包含文字和数字，长度为4
        String code = captcha.getCode();
        //生成sessionId
        String sessionId = String.valueOf(idWorker.nextId());
        log.info("生成校验码:{},会话id:{}",code,sessionId);
        //将sessionId和校验码保存在redis下，并设置缓存中数据存活时间一分钟
        redisTemplate.opsForValue().set(StockConstant.CHECK_PREFIX+sessionId,code,30, TimeUnit.MINUTES);
        //组装响应数据
//        {
//            "code": 1,
//                "data": {
//                    "imageData": "iVBORw0KGgoAAAANSUh...省略...AAAPoAAAAoCAYAAADX=", //base64格式图片
//                    "sessionId": "1479063316897845248" //保存在redis中验证码对应的key，模拟sessioinId
//                         }
//        }
        HashMap<String,String> info = new HashMap<>();
        info.put("sessionId",sessionId);
        info.put("imageData",captcha.getImageBase64());//获取base64格式的图片数据
        //设置响应数据格式
        return R.ok(info);
    }

    /**
     *多条件综合查询用户分页信息
     */
    @Override
    public R<PageResult<SysUserDomain>> getUsers(LoginReqUsers users) {
        PageHelper.startPage(users.getPageNum(), users.getPageSize());
        //调用mapper接口
        List<SysUserDomain> infos = sysUserMapper.getUsers(users.getUsername(),users.getNickName(),users.getStartTime(),users.getEndTime());
        PageInfo<SysUserDomain> pageInfo = new PageInfo<>(infos);
        PageResult<SysUserDomain> result = new PageResult<>(pageInfo);
        return R.ok(result);
    }

    @Override
    public R addUser(AddUserReqVo vo) {
        //判断数据库中是否有该用户
        SysUser dbUser = sysUserMapper.findUserInfoByUserName(vo.getUsername());
        if (dbUser != null) {
            //说明数据库中已有该用户，不能添加
            return R.error(ResponseCode.ACCOUNT_EXISTS_ERROR);
        }
        SysUser user = new SysUser();
        BeanUtils.copyProperties(vo,user);
        user.setId(idWorker.nextId());
        user.setCreateTime(new Date());
        int count = sysUserMapper.addUser(user);
        log.info("count值：{}",count);
        if (count==1) {
            return R.ok(ResponseCode.SUCCESS);
        }else{
            return R.error(ResponseCode.ERROR);
        }
    }

    @Override
    public R deleteUser(List<Long> userIds) {
        int count = sysUserMapper.deleteUser(userIds);
        if (count<=0) {
            return R.error();
        }
        return R.ok();
    }

    /**
     * 根据用户id查询用户信息
     * @param id
     * @return
     */
    @Override
    public R<UserInfoRespVo> getUserInfoById(String id) {
        SysUser user = sysUserMapper.getUserInfoById(Long.parseLong(id));
        if(user!=null){
            UserInfoRespVo info = new UserInfoRespVo();
            BeanUtils.copyProperties(user,info);
            return R.ok(info);
        }else{
            return R.error(ResponseCode.ERROR.getMessage());
        }
    }


    @Override
    public R updateUserInfoById(SysUserUpdateReqVo vo) {
        SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(vo,sysUser);
        int count = sysUserMapper.updateByPrimaryKeySelective(sysUser);
        //返回结果
        if(count>0){
            return R.ok();
        }
        else
            return R.error(ResponseCode.ERROR.getMessage());
    }
}
